module STM4_MPI(
   input                     MPI_RESET,
   input                     MPI_CLK,
   input[15:0]               CPU_ADDR,
   input                     CPU_RW,
   input                     CPU_CSN,
   inout[15:0]               CPU_DATA,

   output reg[15:0]          MPI_ADDR,
   output reg[15:0]          MPI_WD,
   output reg                MPI_RE,
   output reg                MPI_WE,
   input[15:0]               MPI_GLB_REGS_RD,
   input[15:0]               MPI_SOH_0_RD,
   input[15:0]               MPI_SOH_1_RD,
   input[15:0]               MPI_SOH_2_RD,
   input[15:0]               MPI_SOH_3_RD,
   input[15:0]               MPI_FRM_0_RD,
   input[15:0]               MPI_FRM_1_RD,
   input[15:0]               MPI_FRM_2_RD,
   input[15:0]               MPI_FRM_3_RD,
   output reg                MPI_GLB_REGS_CS,
   output reg                MPI_SOH_0_CS,
   output reg                MPI_SOH_1_CS,
   output reg                MPI_SOH_2_CS,
   output reg                MPI_SOH_3_CS,
   output reg                MPI_FRM_0_CS,
   output reg                MPI_FRM_1_CS,
   output reg                MPI_FRM_2_CS,
   output reg                MPI_FRM_3_CS
   ) ;

reg[7:0]                RD_SREG;
reg[7:0]                WR_SREGS;

always @( posedge MPI_RESET or posedge MPI_CLK)  begin
    if ( MPI_RESET==1'b1 )  begin
        RD_SREG[7:0]                 <= 8'd0;
        WR_SREGS[7:0]                <= 8'd0;
    end
    else begin
        RD_SREG[0]                   <= ( CPU_CSN==1'b0 && CPU_RW==1'b1 );
        RD_SREG[7:1]                 <= RD_SREG[6:0];
        WR_SREGS[0]                  <=( CPU_CSN==1'b0 && CPU_RW==1'b0 );
        WR_SREGS[7:1]                <=WR_SREGS[6:0];
    end
end

always @( WR_SREGS )  begin
    if ( WR_SREGS[2]==1'b1 && WR_SREGS[3]==1'b0 )
        MPI_WE                       <=1'b1 ;
    else
        MPI_WE                       <=1'b0 ;
end

always @( RD_SREG )  begin
    if ( RD_SREG[3]==1'b1 && RD_SREG[4]==1'b0 )
        MPI_RE                       <=1'b1 ;
    else
        MPI_RE                       <=1'b0 ;
end

always @( posedge MPI_RESET or posedge MPI_CLK)  begin
   if ( MPI_RESET==1'b1 ) begin
      MPI_WD[15:0]                    <= 16'd0;
      MPI_ADDR[15:0]                  <= 16'd0;
   end
   else begin
      MPI_WD[15:0]                    <= CPU_DATA[15:0];
      MPI_ADDR[15:0]                  <= CPU_ADDR[15:0];
   end
end

//  ++++++                            modules MPI CS map                         ++++++  //
always @( posedge MPI_RESET or posedge MPI_CLK)  begin
   if ( MPI_RESET==1'b1 ) begin
      MPI_GLB_REGS_CS                     <= 1'b0;
      MPI_SOH_0_CS                        <= 1'b0;
      MPI_SOH_1_CS                        <= 1'b0;
      MPI_SOH_2_CS                        <= 1'b0;
      MPI_SOH_3_CS                        <= 1'b0;
      MPI_FRM_0_CS                        <= 1'b0;
      MPI_FRM_1_CS                        <= 1'b0;
      MPI_FRM_2_CS                        <= 1'b0;
      MPI_FRM_3_CS                        <= 1'b0;
   end
   else begin
      MPI_GLB_REGS_CS                     <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h00 );                             // 0x0000-0x00FF
      MPI_SOH_0_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h10 || CPU_ADDR[15:8]==8'h11);     // 0x1000-0x11FF
      MPI_SOH_1_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h12 || CPU_ADDR[15:8]==8'h13);     // 0x1200-0x13FF
      MPI_SOH_2_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h14 || CPU_ADDR[15:8]==8'h15);     // 0x1400-0x15FF
      MPI_SOH_3_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h16 || CPU_ADDR[15:8]==8'h16);     // 0x1600-0x17FF
      MPI_FRM_0_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h08 || CPU_ADDR[15:8]==8'h09);     // 0x0800-0x09FF
      MPI_FRM_1_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h0A || CPU_ADDR[15:8]==8'h0B);     // 0x0A00-0x0BFF
      MPI_FRM_2_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h0C || CPU_ADDR[15:8]==8'h0D);     // 0x0C00-0x0DFF
      MPI_FRM_3_CS                        <= CPU_CSN==1'b0 && ( CPU_ADDR[15:8]==8'h0E || CPU_ADDR[15:8]==8'h0F);     // 0x0E00-0x0FFF
   end
end

// data bus output control
reg[15:0]                CPU_DATA_DRIVE;             // read output data after tri-state control
always @(  CPU_RW or CPU_CSN or MPI_GLB_REGS_RD or MPI_SOH_0_RD or MPI_SOH_1_RD or MPI_SOH_2_RD or MPI_SOH_3_RD or MPI_FRM_0_RD or MPI_FRM_1_RD or MPI_FRM_2_RD or MPI_FRM_3_RD or MPI_GLB_REGS_CS or MPI_SOH_0_CS or MPI_SOH_1_CS or MPI_SOH_2_CS or MPI_SOH_3_CS or MPI_FRM_0_CS or MPI_FRM_1_CS or MPI_FRM_2_CS or MPI_FRM_3_CS) begin
   if ( CPU_CSN==1'b0 && CPU_RW==1'b1 ) begin
      if ( MPI_GLB_REGS_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_GLB_REGS_RD[15:0];
      else if ( MPI_SOH_0_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_SOH_0_RD[15:0];
      else if ( MPI_SOH_1_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_SOH_1_RD[15:0];
      else if ( MPI_SOH_2_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_SOH_2_RD[15:0];
      else if ( MPI_SOH_3_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_SOH_3_RD[15:0];
      else if ( MPI_FRM_0_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_FRM_0_RD[15:0];
      else if ( MPI_FRM_1_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_FRM_1_RD[15:0];
      else if ( MPI_FRM_2_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_FRM_2_RD[15:0];
      else if ( MPI_FRM_3_CS==1'b1 )
         CPU_DATA_DRIVE[15:0]             <= MPI_FRM_3_RD[15:0];
      else
         CPU_DATA_DRIVE[15:0]             <= 16'd0;
   end
   else
      CPU_DATA_DRIVE[15:0]                <= 16'hzzzz;
end
  assign CPU_DATA[15:0]=CPU_DATA_DRIVE;




endmodule
